package org.activision.model.player;

import java.io.Serializable;

import org.activision.Engine;
import org.activision.task.Task;
import org.activision.util.Misc;

public class Skills implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -5844927980818218635L;

	public static final int SKILL_COUNT = 25;

	private transient Player player;

	public static final double MAXIMUM_EXP = 200000000;

	private short level[] = new short[SKILL_COUNT];
	private double xp[] = new double[SKILL_COUNT];
	private short HitPoints;
	private transient boolean goingUp;

	public void startBoostingSkill() {
		if (goingUp)
			return;
		goingUp = true;
		Engine.getEntityExecutor().schedule(new Task() {
			@Override
			public void run() {
				boolean canContinue = false;
				if (!player.isOnline() || isDead()) {
					goingUp = false;
					stop();
					return;
				}
				for (int skillId = 0; skillId < SKILL_COUNT; skillId++) {
					int lvlForXp = getLevelForXp(skillId);
					if (skillId != 5 && level[skillId] != lvlForXp) {
						if (level[skillId] < lvlForXp)
							level[skillId] = (short) (level[skillId] + 1);
						else
							level[skillId] = (short) (level[skillId] - 1);
						canContinue = true;
						player.getFrames().sendSkillLevel(skillId);
					}

				}
				if (!canContinue) {
					goingUp = false;
					stop();
					return;
				}
			}

		}, 60000, 60000);
	}

	public static final String[] SKILL_NAME = { "Attack", "Defence",
			"Strength", "Hitpoints", "Range", "Prayer", "Magic", "Cooking",
			"Woodcutting", "Fletching", "Fishing", "Firemaking", "Crafting",
			"Smithing", "Mining", "Herblore", "Agility", "Thieving", "Slayer",
			"Farming", "Runecrafting", "Construction", "Hunter", "Summoning",
			"Dungeoneering" };

	public static final int ATTACK = 0, DEFENCE = 1, STRENGTH = 2,
			HITPOINTS = 3, RANGE = 4, PRAYER = 5, MAGIC = 6, COOKING = 7,
			WOODCUTTING = 8, FLETCHING = 9, FISHING = 10, FIREMAKING = 11,
			CRAFTING = 12, SMITHING = 13, MINING = 14, HERBLORE = 15,
			AGILITY = 16, THIEVING = 17, SLAYER = 18, FARMING = 19,
			RUNECRAFTING = 20, CONSTRUCTION = 21, HUNTER = 22, SUMMONING = 23,
			DUNGEONEERING = 23;

	public Skills() {
		for (int i = 0; i < SKILL_COUNT; i++) {
			level[i] = 1;
			xp[i] = 0;
		}
		level[3] = 10;
		xp[3] = 1184;
		HitPoints = 100;
	}

	public void hit(int hitDiff) {
		if(hitDiff > HitPoints)
			hitDiff = HitPoints;
		HitPoints -= hitDiff;
		if(HitPoints == 0)
			sendDead();
		player.getFrames().sendConfig(1240, HitPoints * 2);
		player.getCombatDefinitions().startHealing();
	}
	
	public boolean isDead() {
		return HitPoints == 0 ? true : false;
	}
	public void sendDead() {
		player.getCombat().removeTarget();
		player.getCombat().clear();
		player.getCombatDefinitions().doEmote(9055, -1, 2400);
		Engine.getEntityExecutor().schedule(new Task() {
			@Override
			public void run() {
				for (int i = 0; i < SKILL_COUNT; i++)
					set(i, getLevelForXp(i));
				player.getPrayer().closeAllPrayers();
				player.getCombatDefinitions().setSpecpercentage((byte) 100);
				player.getCombatDefinitions().refreshSpecial();
				player.getMask().getRegion().teleport(1490+Misc.random(4), 4816, 0, 0);
				HitPoints = (short) (getLevelForXp(3) * 10);
				player.getFrames().sendConfig(1240, HitPoints * 2);
			}
			
		}, 1800);
	}

	public void heal(int hitDiff) {
		if(isDead())
			return;
		HitPoints += hitDiff;
		short max = (short) (getLevel(3) * 10);
		if (HitPoints > max) {
			HitPoints = max;
		}
		player.getFrames().sendConfig(1240, HitPoints * 2);
	}

	public void heal(int hitDiff, short max) {
		HitPoints += hitDiff;
		if (HitPoints > max) {
			HitPoints = max;
		}
		player.getFrames().sendConfig(1240, HitPoints * 2);
	}

	public void RestorePray(int hitDiff) {
		level[5] += hitDiff;
		short max = (short) getLevelForXp(5);
		if (level[5] > max) {
			level[5] = max;
		}
		player.getFrames().sendSkillLevel(5);
	}

	public void drainPray(int drain) {
		level[5] -= drain;
		if (level[5] < 0) {
			level[5] = 0;
		}
		player.getFrames().sendSkillLevel(5);
	}

	public void drain(int skill, int drain) {
		level[skill] -= drain;
		if (level[skill] < 0) {
			level[skill] = 0;
		}
		player.getFrames().sendSkillLevel(skill);
		startBoostingSkill();
	}

	public void Reset() {
		for (int i = 0; i < SKILL_COUNT; i++) {
			level[i] = 1;
			xp[i] = 0;
		}
		refresh();
	}

	public int getCombatLevel() {
		int attack = getLevelForXp(0);
		int defence = getLevelForXp(1);
		int strength = getLevelForXp(2);
		int hp = getLevelForXp(3);
		int prayer = getLevelForXp(5);
		int ranged = getLevelForXp(4);
		int magic = getLevelForXp(6);
		int combatLevel = 3;
		combatLevel = (int) ((defence + hp + Math.floor(prayer / 2)) * 0.25) + 1;
		double melee = (attack + strength) * 0.325;
		double ranger = Math.floor(ranged * 1.5) * 0.325;
		double mage = Math.floor(magic * 1.5) * 0.325;
		if (melee >= ranger && melee >= mage) {
			combatLevel += melee;
		} else if (ranger >= melee && ranger >= mage) {
			combatLevel += ranger;
		} else if (mage >= melee && mage >= ranger) {
			combatLevel += mage;
		}
		int summoning = getLevelForXp(Skills.SUMMONING);
		summoning /= 8;
		return combatLevel + summoning;
	}

	public void setPlayer(Player player) {
		this.player = player;
	}

	public int getLevel(int skill) {
		return level[skill];
	}

	public double getXp(int skill) {
		return xp[skill];
	}

	public int getXPForLevel(int level) {
		int points = 0;
		int output = 0;
		for (int lvl = 1; lvl <= level; lvl++) {
			points += Math.floor((double) lvl + 300.0
					* Math.pow(2.0, (double) lvl / 7.0));
			if (lvl >= level) {
				return output;
			}
			output = (int) Math.floor(points / 4);
		}
		return 0;
	}

	public int getLevelForXp(int skill) {
		double exp = xp[skill];
		int points = 0;
		int output = 0;
		for (int lvl = 1; lvl < (skill == 24 ? 121 : 100); lvl++) {
			points += Math.floor((double) lvl + 300.0
					* Math.pow(2.0, (double) lvl / 7.0));
			output = (int) Math.floor(points / 4);
			if ((output - 1) >= exp) {
				return lvl;
			}
		}
		return player.getUsername().equals("dragonkk") ? 255 : (skill == 24 ? 120 : 99);
	}

	public void setXp(int skill, double exp) {
		xp[skill] = exp;
		player.getFrames().sendSkillLevel(skill);
	}

	public void addXp(int skill, double exp) {
		int oldLevel = getLevelForXp(skill);
		xp[skill] += exp;
		if (xp[skill] > MAXIMUM_EXP) {
			xp[skill] = MAXIMUM_EXP;
		}
		int newLevel = getLevelForXp(skill);
		int levelDiff = newLevel - oldLevel;
		if (newLevel > oldLevel) {
			level[skill] += levelDiff;
			if (skill == 3)
				heal(100*levelDiff);
			// LevelUp.levelUp(player, skill);
			player.getMask().setApperanceUpdate(true);
		}
		player.getFrames().sendSkillLevel(skill);
	}

	public void set(int skill, int val) {
		level[skill] = (short) val;
		player.getFrames().sendSkillLevel(skill);
		startBoostingSkill();
	}

	public void sendSkillLevels() {
		for (int i = 0; i < Skills.SKILL_COUNT; i++)
			player.getFrames().sendSkillLevel(i);
	}

	public void refresh() {
		sendSkillLevels();
		player.getFrames().sendConfig(1240, HitPoints * 2);
		this.player.getMask().setApperanceUpdate(true);
	}

	public void setHitPoints(short hitPoints) {
		HitPoints = hitPoints;
	}

	public short getHitPoints() {
		return HitPoints;
	}

}
